package com.cloudlinkscm.base.authcenter.domain;

import com.cloudlinkscm.base.authcenter.assembler.PublicResource2TenantResourceAssembler;
import com.cloudlinkscm.base.authcenter.assembler.TenantResourceCreateDto2TenantResourceAssembler;
import com.cloudlinkscm.base.authcenter.constant.ResourceTypeEnum;
import com.cloudlinkscm.base.authcenter.dao.PublicResourceDao;
import com.cloudlinkscm.base.authcenter.dao.TenantResourceDao;
import com.cloudlinkscm.base.authcenter.model.PublicResource;
import com.cloudlinkscm.base.authcenter.model.Resource;
import com.cloudlinkscm.base.authcenter.model.TenantResource;
import com.cloudlinkscm.base.authcenter.model.bo.NodeAllResourceBO;
import com.cloudlinkscm.base.authcenter.model.dto.*;
import com.cloudlinkscm.base.authcenter.model.dto.ResourceTree;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author : tac
 * @date : 31/07/2017
 */
@Component
public class AbstractTenantResourceManager {

	@Autowired
    private TenantResourceDao tenantResourceDao;
	@Autowired
    private PublicResourceDao publicResourceDao;

	@Autowired
    private AbstractPublicResourceManager publicResourceManager;
    @Autowired
    private PublicResource2TenantResourceAssembler publicResource2TenantResourceAssembler;
    @Autowired
    private TenantResourceCreateDto2TenantResourceAssembler tenantResourceCreateDto2TenantResourceAssembler;
	@Autowired
    private ResourceManager resourceManager;

    /**
     * 复制公共资源到租户资源
     *
     * @param publicResourceIds 公共资源id
     * @param tenantId 租户id
     * @return
     */
    public int fork(List<String> publicResourceIds, String tenantId){
//        List<PublicResource> publicResources = publicResourceManager.getDao().selectByPrimaryKeys(publicResourceIds);
        //todo::
        return 0;
    }

    public TenantResource createModule(TenantResourceCreateDto dto){
        return doCreate(dto, ResourceTypeEnum.MODULE);
    }
    public TenantResource createMenu(SubTenantResourceCreateDto dto){
        return doCreate(dto, ResourceTypeEnum.MENU);
    }
    public TenantResource createPage(PermissionTenantResourceCreateDto dto){
        return doCreate(dto, ResourceTypeEnum.PAGE);
    }
    public TenantResource createAction(PermissionTenantResourceCreateDto dto){
        return doCreate(dto, ResourceTypeEnum.ACTION);
    }

    /**
     * 删除租户资源
     *
     * <p>同时删除其所有子资源</p>
     */
    public int delete(String id){

	    // TODO: 需要考虑 已分配出去的 用户资源
	    return tenantResourceDao.deleteByPrimaryKeyRecursively(id);
    }

    /**
     * 根据公共资源id删除所有关联的租户资源及其子资源
     */
    public int deleteByPubId(String publicResourceId) {
        int rowNum = 0;
        List<TenantResource> ls = listByPubId(publicResourceId);
        if (CollectionUtils.isEmpty(ls)) {
        	return rowNum;
        }
        for (TenantResource r : ls) {
            rowNum += delete(r.getId());
        }
        return rowNum;
    }


    public List<PublicResource> removalDistribution(List<PublicResource> publicResourceList,
                                                    List<TenantResource> tenantResourceList) {

	    Map<String, PublicResource> publicResourceMap = com.cloudlinkscm.loms.utils.CollectionUtils.buildMap(
			    publicResourceList, String.class, PublicResource.class, "resourceKey");


	    List<PublicResource> removePublicResourceList = new ArrayList<>();
	    for (TenantResource tenantResource : tenantResourceList) {
		    if (publicResourceMap.containsKey(tenantResource.getResourceKey())) {
			    removePublicResourceList.add(publicResourceMap.get(tenantResource.getResourceKey()));
		    }
	    }
	    publicResourceList.removeAll(removePublicResourceList);
		return publicResourceList;
    }

    private List<TenantResource> listByPubId(String publicResourceId) {
        TenantResource o = new TenantResource();
        o.setPublicResourceId(publicResourceId);
        return tenantResourceDao.select(o);
    }

    public List<ResourceTree> tree(List<TenantResource> tenantResourceList) {
    	return resourceManager.buildResourceTree(
    			resourceManager.convertResource(tenantResourceList));
    }

	public TenantResource convertToTenantResource(String tenantId, String pid, PublicResource basePublicResource) {
		TenantResource tenantResource = new TenantResource();
		BeanUtils.copyProperties(basePublicResource, tenantResource);

		// set id
		tenantResource.setId(null);
		tenantResource.setPid(pid);
		tenantResource.setTenantId(tenantId);
		tenantResource.setPublicResourceId(basePublicResource.getId());

		return tenantResource;
	}


	@Transactional
	public Integer moveIn(String tenantId, List<String> nodeIds) {

    	int result = 0;

		List<NodeAllResourceBO> nodeAllResourceBOList =
				resourceManager.positionNodes(
						resourceManager.convertResource(publicResourceDao.selectAll()),
						resourceManager.convertResource(publicResourceDao.selectByIds(nodeIds)));

		for (NodeAllResourceBO nodeAllResourceBO : nodeAllResourceBOList) {

			List<ResourceTree<PublicResource>> treeList = resourceManager.buildResourceTree(
					nodeAllResourceBO.getDistributionResource());

			for (ResourceTree<PublicResource> tree : treeList) {
				result = recursiveInsert(tree, ResourceTree.TREE_ROOT, tenantId);
			}
		}
		return result;
	}

	@Transactional
	public int moveOut(List<String> nodeIds) {

		int result = 0;
		List<Resource> allResource = resourceManager.convertResource(tenantResourceDao.selectAll());
		List<Resource> positionResources = resourceManager.convertResource(tenantResourceDao.selectByIds(nodeIds));
		List<NodeAllResourceBO> nodeAllResourceBOList = resourceManager.downFind(allResource, positionResources);


		for (NodeAllResourceBO<Resource> nodeAllResourceBO : nodeAllResourceBOList) {

			// 没有子节点的节点
			String rootNodeId = nodeAllResourceBO.getPositionResource().getId();
			if (!CollectionUtils.isEmpty(nodeAllResourceBO.getDistributionResource())) {
				result = tenantResourceDao.deleteByIds(com.cloudlinkscm.loms.utils.CollectionUtils.buildSet(
						nodeAllResourceBO.getDistributionResource(), String.class, "id"));

				rootNodeId = resourceManager.rootNodeId(nodeAllResourceBO.getDistributionResource());
			}

			result += recursiveDelete(rootNodeId);
		}

		return result;
	}


	private int recursiveInsert(ResourceTree<PublicResource> tree,
	                                       String pid,
	                                       String tenantId) {
		int index = 0;
		String nextPid;
		PublicResource publicResource = tree.getData();

		// 检查数据库是否存在，不存在才添加
		TenantResource baseTenantResource = tenantResourceDao.selectByTenantIdAndResourceKey(
				tenantId, publicResource.getResourceKey());

		if (baseTenantResource == null) {
			TenantResource rootResource = convertToTenantResource(tenantId, pid, tree.getData());
			rootResource.setId(null);
			tenantResourceDao.insert(rootResource);

			// 设置 next pid
			nextPid = rootResource.getId();
		}
		else {
			// 设置 next pid
			nextPid = baseTenantResource.getId();
		}

		if (!CollectionUtils.isEmpty(tree.getChildren())) {
			for (ResourceTree treeDTO : tree.getChildren()) {
				index += recursiveInsert(treeDTO, nextPid, tenantId);
			}
		}

		return ++index;
	}

	private int recursiveDelete(String parentNoeId) {
    	int result = 0;
		TenantResource tenantResource = tenantResourceDao.selectByPrimaryKey(parentNoeId);
		List<TenantResource> tenantResourceList = tenantResourceDao.selectByPid(parentNoeId);
		if (CollectionUtils.isEmpty(tenantResourceList)) {

			// 不是 root 节点，继续找
			result = tenantResourceDao.deleteByPrimaryKey(parentNoeId);
			if (!ResourceTree.TREE_ROOT.equals(tenantResource.getPid())) {
				recursiveDelete(tenantResource.getPid());
			}
		}
		return result;
	}


	protected TenantResource doCreate(TenantResourceCreateDto dto, ResourceTypeEnum type) {
        int rowNum = 0;
        TenantResource resource  = tenantResourceCreateDto2TenantResourceAssembler.assemble(dto, type);
        rowNum += tenantResourceDao.insert(resource);
        return resource;
    }


	/**
	 * 租户资源：
	 *
	 * <p>
	 *     返回构建的  {@link TenantResourceDistributionDTO}
	 *     两个属性：{@link TenantResourceDistributionDTO#distributionTree} 已分配权限
	 *     另一个：{@link TenantResourceDistributionDTO#notDistributionTree} 未分配权限
	 * </p>
	 *
	 * @param publicResourceList 公共资源
	 * @param tenantResourceList 租户资源
	 * @return
	 */
	public TenantResourceDistributionDTO getResource(List<PublicResource> publicResourceList,
	                                                 List<TenantResource> tenantResourceList) {

		// 构建 Resource tree
    	List<ResourceTree> resourceTrees = resourceManager.buildResourceTree(
    			resourceManager.convertResource(publicResourceList));

    	// 构建 resource key
		Map<String, TenantResource> tenantResourceMap = com.cloudlinkscm.loms.utils.CollectionUtils.buildMap(
				tenantResourceList, String.class, TenantResource.class, "resourceKey");

		// 开始 构建一个新的 resource
		Set<Resource> repeatResource = new HashSet<>(resourceManager.buildNewResource(resourceTrees, tenantResourceMap));

		return new TenantResourceDistributionDTO(
				resourceManager.buildResourceTree(resourceManager.convertResource(new ArrayList<>(repeatResource))),
				resourceManager.buildResourceTree(resourceManager.convertResource(tenantResourceList)));
	}
}
